﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Core.Model.Data
{
    public class OctetString : IComparer<OctetString>, IEnumerable<byte>, IEquatable<byte[]>,IEquatable<string>, ICloneable,IComparable<OctetString>     {
        public byte[] Value { get; set; }

        private string stringValue;
        
        public string StringValue
        {
            get
            {
                return stringValue ?? (stringValue = AsciiEncoding.GetString(Value));
            }
        }
        
        private static readonly OctetString empty = new OctetString("");
        
        public static OctetString Empty
        {
            get { return empty; }
        }

        public OctetString(byte[] value)
        {
            if (value == null)
                throw new ArgumentException("Value can not be null", "value");

            this.Value = value;
        }
        public OctetString(string value)
        {
            if (value == null)
                throw new ArgumentException("Value can not be null", "value");

            this.stringValue = value;
            this.Value = AsciiEncoding.GetBytes(value);;
            
        }

        public OctetString(int value)
            : this(value.ToString())
        {
        }

        private readonly ASCIIEncoding AsciiEncoding = new ASCIIEncoding();

        
        public int Length
        {
            get { return Value.Length; }
        }


        public override string ToString()
        {
            return StringValue;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals (obj,this))
                return true;

            if (ReferenceEquals(obj,null) || !(obj is OctetString))
                return false;

            
            var o = obj as OctetString;
            
            return StringValue.Equals(o.StringValue);
        }

        public bool Equals(OctetString obj)
        {
            if (ReferenceEquals (obj,this))
                return true;

            if (ReferenceEquals(obj,null))
                return false;
            
            
            return StringValue.Equals(obj.StringValue);
        }

        public override int GetHashCode()
        {
            return StringValue.GetHashCode();
        }

        public static bool operator ==(OctetString a, OctetString b)
        {
            // If both are null, or both are same instance, return true.
            if (System.Object.ReferenceEquals(a, b))
            {
                return true;
            }

            // If one is null, but not both, return false.
            if (((object) a == null) || ((object) b == null))
            {
                return false;
            }

            // Return true if the fields match:
            return a.StringValue.Equals(b.StringValue);
        }

        public static bool operator !=(OctetString a, OctetString b)
        {
            return !(a == b);
        }

        public int CompareTo(OctetString value)
        {
            return StringValue.CompareTo(value.ToString());
        }

        public OctetString Substring(int i, int i1)
        {
            return new OctetString(StringValue.Substring(i, i1));
        }

        public int IndexOf(OctetString value, int i)
        {
            // <pex>
            if (value == (OctetString)null)
                throw new ArgumentNullException("value");
            // </pex>
            return StringValue.IndexOf(value.StringValue, i);
        }

        public OctetString Append(OctetString value)
        {
            //this.Value = Enumerable.Concat<byte>(this.Value, value.Value).ToArray();
            
            return new OctetString(StringValue + value.StringValue);
            //this.Value = AsciiEncoding.GetBytes(stringValue + value.stringValue);

            //this.stringValue = null; //reset cached string
            
        }

        public bool StartsWith(string s)
        {
            return StringValue.StartsWith(s);
        }

        public OctetString Remove(int i, int i1)
        {
            return new OctetString(StringValue.Remove(i, i1));
        }

        #region IEnumerable<byte> Members

        public IEnumerator<byte> GetEnumerator()
        {
            return (IEnumerator<byte>) Value.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return Value.GetEnumerator();
        }

        #endregion

        #region IComparer<OctetString> Members

        public int Compare(OctetString x, OctetString y)
        {
            return x.StringValue.CompareTo(y.stringValue);
        }

        #endregion

        
        #region IEquatable<byte[]> Members

        public bool Equals(byte[] other)
        {
            return Value.Equals(other);
        }

        #endregion

        #region IEquatable<string> Members

        public bool Equals(string other)
        {
            return StringValue.Equals(other);
        }

        #endregion

        #region ICloneable Members

        public object Clone()
        {
            return new OctetString((byte[])Value.Clone());
        }

        #endregion

        #region IComparable<OctetString> Members

        int IComparable<OctetString>.CompareTo(OctetString other)
        {
            return StringValue.CompareTo(other.stringValue);
        }

        #endregion
    }
}
